class MyInteraction extends Interaction;
/*************************************
 * Levetation Idea:
 * - click (and hold) mouse1 to shoot/select object to be lifted
 * - object goes into 'hover' state where it is suspended in the air just off
 *   the ground
 * - player uses mousewheelup/mousewheel down to move the object in the UpDown axis
 * - player uses 'w' and 's' to move the object in the ForwardBack axis
 * - player uses 'a' and 'd' to move the object in the LeftRight axis
 * - when mouse1 is released the object is propelled in the horizontal plane in
 *   the wasd direction that was last registered (or just falls to the ground if
 *   no wasd keys were pressed)
 */

var bool bLev, bX, bY, bZ;
var vector LevAxis;  //(x, y, z), set by keypresses
var vector x, y, z;
var EnyaraPlayerController MPC;
var LevObject L;
var LevManager LManager;
var bool AxisDir; //+ or - direction along axis
var bool pos, neg;
var Interactions.EInputKey FrontKey, BackKey, UpKey, DownKey, LeftKey, RightKey;
var bool ShiftDown;
var String typedStr;

var float tapStamp, tapAcc;

var bool bIgnoreKeys;
var float timeCounter;
var bool bFlushStr;
const InputWindow = 0.5;
var bool bLeftMouseDown; //bMovementKeyDown, uDown, dDown, lDown, rDown, fDown, bDown;
var int debugcount;
var int cycleCount; //reset to zero on mouse1 press

struct KeyDown{
    var bool Down1, Down2, bLock;
    var float LastDownTime;
};
var bool uDown, dDown, lDown, rDown, bDown;
var bool wheelUpPress, wheelDownPress;
var KeyDown fDown;
var bool DoubleTap;

const mWheelTimeBetween = 0.4; //since mousewheel has no 'release', simulate time between keydown and keyup
var float mWheelAcc;

var bool bIgnoreMovementKeys;

//variables for W, W, Mouse1 Push
//keychain: Wdown1 -> Wup1 -> Wdown2 -> Mouse1Down1
const keychainWindow = 2.0;
var bool kcWdown1, kcWup1, kcWdown2, kcMouse1Down1;
var bool doubleTapPush;        //used while not leving
var float KCPushTimeStamp;

//variables for S, S, Mouse1 Pull
//keychain: Sdown1 -> Sup1 -> Sdown2 -> Mouse1Down1
var bool kcSdown1, kcSup1, kcSdown2;
var bool doubleTapPull;        //used while not leving
var float KCPullTimeStamp;

var bool doubleTapPullWhileLev; //used while leving


function Initialized()
{
   if (MPC == none) MPC = EnyaraPlayerController(ViewportOwner.Actor);
   if (MPC != none && LManager == none) LManager = MPC.LManager;
   Log("MyInteraction Initialize(): MPC"@MPC.name@"LManager"@LManager.name);
}

function FlushStr(){
    TypedStr = "";
}

function Tick(float dt){
    if (MPC != none && LManager != none && LManager.AcceptingInput() && bLeftMouseDown && LManager.LevTarget.IsInState('LevObject')){
        //xxViewportOwner.Actor.ClientMessage("START HOVERING!!!!!");
        log("Interaction changes LevObject state to 'Hovering'");
        LManager.LevTarget.GotoState('Hovering');
       // bRequiresTick = false;
    }
    else if (LManager != none && LManager.AcceptingInput() && bLeftMouseDown && LManager.LevTarget.IsInState('Hovering') && bIgnoreMovementKeys){
        LManager.moveSpringAttachLocation(uDown, dDown, rDown, lDown, fDown.Down1, bDown);
        //on initial press, uDown or dDown is set to true...mousewheel has no release
        //to indicate when to set these bools to false, so the human delay is simulated
        //by a 'sensitivity' value...pretend to hold 'mousewheel' button for X seconds
        mWheelAcc += dt;  //when time has exceeded the threshold, set bool to false (like release)
        if (mWheelAcc > mWheelTimeBetween){
            if (uDown) uDown = false;
            if (dDown) dDown = false;
            mWheelAcc = 0;
        }
    }
    if (DoubleTap){
        tapAcc += dt;
        //if (tapAcc > 0.5){
        //    DoubleTap = false;
        //    tapAcc = 0;
        //}
        //LManager.printscreen("DOUBLETAP!!!");
        LManager.setdoubletap(true);
        DoubleTap = false;
        if (self.bIgnoreMovementKeys == true) self.bIgnoreMovementKeys = false;
     //   self.InitTakeDown();
    }
    else if (self.doubleTapPullWhileLev){
        /*LManager.printscreen("doubletap pull (while lev)!!!!!");
        LManager.setDoubleTapPullWhileLev(true);
        self.doubleTapPullWhileLev = false;
        LManager.LevTarget.bIsPulledWhileLev = true;  //needed to stop object before hitting player...
                                              //   normally set by pull damage type, but since no damage
                                              //   done while already leving this is a ghetto workaround
                                              //   ...reset to false in levobject tick
        */
        Lmanager.printscreen("SMOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOTH");
        Lmanager.LevTarget.GotoState('SmoothMoving');
        self.doubleTapPullWhileLev = false;

        //if (self.bIgnoreMovementKeys == true) self.bIgnoreMovementKeys = false;
    }


    if (self.doubleTapPush){
         LManager.printscreen("doubletap push!!!!");
         LevGun(ViewportOwner.Actor.Pawn.Weapon).setDType(class'Enyara.DamTypePush');
         self.kcreset();

        //printbools();
        //:TODO: set a bool in levmanager and have levemanager's tick apply the push
    }
    else if (self.doubleTapPull){
        LManager.printscreen("doubletap pull!!!!");
        LevGun(ViewportOwner.Actor.Pawn.Weapon).setDType(class'Enyara.DamTypePull');
        self.kcreset();
        //self.doubleTapPull = false;


    }

   /* else if (MPC != none && LManager != none && LManager.AcceptingInput() && bLeftMouseDOwn && bMovementKeyDown && LManager.LevTarget.IsInState('Hovering')){
        ViewportOwner.Actor.ClientMessage("START MOVING!!!!!");
        log("Interaction changes LevObject state to 'Moving'");
    }*/
}

function printbools(){
    log("BOOLSTART");
    log("bLeftMouseDown:"@bLeftMouseDown);
    log("kcWdown1:"@kcWdown1);
    log("kcWup1:"@kcWup1);
    log("kcWdown2:"@kcWdown2);
    log("kcMouse1Down1:"@kcMouse1Down1);
    log("doubleTapPush:"@doubleTapPush);
}


function bool KeyEvent(EInputKey Key, EInputAction Action, FLOAT Delta )
{
/*******************
 * Requirements for initial levitation:
 * - LManager.AcceptingInput() = true
 * - LeftMouse button held down
 */
    //if (Action == IST_Press) LManager.printscreen(key);
    if (Action == IST_Press && Key == IK_LeftMouse && !bLeftMouseDown){
            bLeftMouseDown = true;
            cycleCount=0;
    }
    //if (MPC != none && LManager != none && LManager.AcceptingInput() && bLeftMouseDown){
    if (MPC != none && LManager != none && LManager.AcceptingInput() && bLeftMouseDown){
        //each pass, get a polling of what is pushed down at the time. only one direction
        //from each of the 3 axes can be registered at a time.
        if (debugcount <= 0){
            debugcount++;
            log("Interaction now accepting input"@debugcount);
            //log(string(LManager.LevTarget.GetStateName()));
        }

        if (Action == IST_Press && (LManager.LevTarget.IsInState('Hovering') || LManager.LevTarget.IsInState('PlayerHolding') ) ){
            if (Action == IST_Press && Key == 236 ){
                //log(LManager.getLevelSeconds()$":"@Key@"pressed");
                //LManager.printscreen(Key);
                uDown = true;
                dDown = false;
            }
            else if (Action == IST_Press && Key == 237 ){
               //log(LManager.getLevelSeconds()$":"@Key@"pressed");
               uDown = false;
               dDown = true;
              // LManager.printscreen(Key);
            }
            else {
                uDown = false;
                dDown = false;
            }

            if (Key == UpKey) uDown = true;
            if (Key == DownKey) dDown = true;
            if (Key == LeftKey) lDown = true;
            if (Key == RightKey) rDown = true;
            if (Key == BackKey) bDown = true;
            if (Key == FrontKey){
                //LManager.printScreen(Lmanager.Getlevelseconds()@fDown.LastDownTime);
                if ((LManager.getLevelSeconds() - fDown.LastDownTime < 0.5) && !fDown.Down1){ //six frames to double tap
                    fDown.Down2 = true;
                    DoubleTap = true;
                }
                else{
                    fDown.Down1 = true;
                    fDown.Down2 = false;
                }

                fDown.LastDownTime = LManager.getLevelSeconds();
            }

            //pull towards while already leving (note: release part (Sup) is in next section
            if (Action == IST_Press && Key == self.BackKey){
                if (!self.kcSdown1){
                    self.KCPullTimeStamp = MPC.Level.TimeSeconds;
                    self.kcSdown1 = true;
                    LManager.printscreen("Sd1");
                }
                else if (!self.kcSdown2 && kcSup1 == true && (MPC.Level.TimeSeconds - self.KCPullTimeStamp < self.keychainWindow)){
                    self.kcSdown2 = true;
                    self.doubleTapPullWhileLev = true;
                    LManager.printscreen("Sd2");

                }
                else {
                    //if past window, reset
                    if (self.kcSup1 && MPC.Level.TimeSeconds - self.KCPullTimeStamp > self.keychainWindow){
                        kcReset();
                        //since this is the first key in the chain, we have to do more
                        //than just reset, since then that late click wont count towards the
                        //chain again and it will just reset instead of reset and restart
                        self.KCPullTimeStamp = MPC.Level.TimeSeconds;
                        self.kcSdown1 = true;
                        LManager.printscreen("Sd1 (new)");
                    }
                }
            }
        }

        if (Action == IST_Release && (LManager.LevTarget.IsInState('Hovering') || LManager.LevTarget.IsInState('PlayerHolding'))){
            if (Key == UpKey) uDown = false;
            if (Key == DownKey) dDown = false;
            if (Key == LeftKey) lDown = false;
            if (Key == RightKey) rDown = false;
            if (Key == BackKey) bDown = false;
            if (Key == FrontKey){
                fDown.Down1 = false;
                fDown.Down2 = false;
            }

            if (Action == IST_Release && Key == self.BackKey && kcSdown1 == true){
                if (!self.kcSup1 && MPC.Level.TimeSeconds - self.KCPullTimeStamp < self.keychainWindow){
                    self.kcSup1 = true;
                    LManager.printscreen("Su1");
                }
                else{
                    kcReset();
                }
            }
        }

        //double-tap

        //Mouse Release (finished leving)
        if ((Action == IST_Release && Key == IK_LeftMouse) || !LManager.AcceptingInput()){
            bLeftMouseDown = false;
            uDown = false;
            dDown = false;
            lDown = false;
            rDown = false;
            bDown = false;
            fDown.Down1 = false;
            self.bIgnoreMovementKeys = false;
            //ShiftDown = false;
            //log("LEFTMOUSE:"@bLeftMouseDown);
            debugcount--;
            log("Interaction no longer accepting input"@debugcount);
            return false;

        }

        //steady cam
        if (Action == IST_Release && Key == IK_Shift) { shiftDown = false; }

        if (Action == IST_Press && Key == IK_Shift){
            //LManager.printscreen("KEYPRESS SHIFT");
            ShiftDown = true;
        }
        //log("shiftdown:"@shiftdown@"bignoremovementkeys:"@bIgnoreMovementKeys);
        if (ShiftDown && !bIgnoreMovementKeys){
            LManager.ignoreMovementKeys();
            //MPC.ClientMessage("SHIFT HEEEEEEEEEEEEEEEEEEEEEELLLLLLLLLLLLLDDDDDDDDD");
            self.bIgnoreMovementKeys = true;
        }
        else if (!ShiftDown && bIgnoreMovementKeys){
            LManager.restoreMovementKeys();
            self.bIgnoreMovementKeys = false;
        }
        //unset stuff after throw, so controls dont get locked out
        else if (ShiftDown && bIgnoreMovementKeys && DoubleTap){
            LManager.restoreMovementKeys();
            self.bIgnoreMovementKeys = false;
            if (ShiftDown) ShiftDown = false;
        }

        return false;
    }

    //###############################################handle double-tap-push/pull-bools
    if (MPC != none && !bLeftMouseDown){
        //****** PUSH *******//
        if (Action == IST_Press && Key == self.FrontKey){
            if (!self.kcWdown1){
                self.KCPushTimeStamp = MPC.Level.TimeSeconds;
                self.kcWdown1 = true;
                LManager.printscreen("Wd1");
            }
            else if (!self.kcWdown2 && kcWup1 == true && (MPC.Level.TimeSeconds - self.KCPushTimeStamp < self.keychainWindow)){
                self.kcWdown2 = true;
                LManager.printscreen("Wd2");
            }
            else {
                //if past window, reset
                if (self.kcWup1 && MPC.Level.TimeSeconds - self.KCPushTimeStamp > self.keychainWindow){
                    kcReset();
                    //since this is the first key in the chain, we have to do more
                    //than just reset, since then that late click wont count towards the
                    //chain again and it will just reset instead of reset and restart
                    self.KCPushTimeStamp = MPC.Level.TimeSeconds;
                    self.kcWdown1 = true;
                    LManager.printscreen("Wd1 (new)");
                }
            }
        }
        else if (Action == IST_Release && Key == self.FrontKey && kcWdown1 == true){
            if (!self.kcWup1 && MPC.Level.TimeSeconds - self.KCPushTimeStamp < self.keychainWindow){
                self.kcWup1 = true;
                LManager.printscreen("Wu1");
            }
            else{
                kcReset();
            }
        }

        //****** PULL *******//
        else if (Action == IST_Press && Key == self.BackKey){
            if (!self.kcSdown1){
                self.KCPullTimeStamp = MPC.Level.TimeSeconds;
                self.kcSdown1 = true;
                LManager.printscreen("Sd1");
            }
            else if (!self.kcSdown2 && kcSup1 == true && (MPC.Level.TimeSeconds - self.KCPullTimeStamp < self.keychainWindow)){
                self.kcSdown2 = true;
                LManager.printscreen("Sd2");
            }
            else {
                //if past window, reset
                if (self.kcSup1 && MPC.Level.TimeSeconds - self.KCPullTimeStamp > self.keychainWindow){
                    kcReset();
                    //since this is the first key in the chain, we have to do more
                    //than just reset, since then that late click wont count towards the
                    //chain again and it will just reset instead of reset and restart
                    self.KCPullTimeStamp = MPC.Level.TimeSeconds;
                    self.kcSdown1 = true;
                    LManager.printscreen("Sd1 (new)");
                }
            }
        }
        else if (Action == IST_Release && Key == self.BackKey && kcSdown1 == true){
            if (!self.kcSup1 && MPC.Level.TimeSeconds - self.KCPullTimeStamp < self.keychainWindow){
                self.kcSup1 = true;
                LManager.printscreen("Su1");
            }
            else{
                kcReset();
            }
        }
    }
    //******** END PUSH/PULL W/S MANAGEMENT *****//
    //now deal with the mouseclick (same key for both)
    else if (!kcMouse1Down1 && Action == IST_Press && Key == IK_LeftMouse){
        //mouseclick for doubletap push
        if (!self.doubleTapPush && kcWdown2 == true){
            if (MPC.Level.TimeSeconds - self.KCPushTimeStamp < self.keychainWindow){
                self.kcMouse1Down1 = true;
                self.doubleTapPush = true;
                LManager.printscreen("Mc1");
                printbools();
            }
            else{
                kcReset();
            }
        }
        //mouseclick for doubletap pull
        else if (!self.doubleTapPull && kcSdown2 == true){
            if (MPC.Level.TimeSeconds - self.KCPullTimeStamp < self.keychainWindow){
                self.kcMouse1Down1 = true;
                self.doubleTapPull = true;
                LManager.printscreen("Mc1");
                printbools();
            }
            else{
                kcReset();
            }

        }
    }
    //end double-tap-push/pull-bools #################################################################

    //if mouse1 is released and it was never aimed at a target, switch off btick on release
    if (Action == IST_Release && Key == IK_LeftMouse){ //&& !bLeftMouseDown){
            bLeftMouseDown = false;
           // MPC.ClientMessage("SHIFT HEEEEEEEEEEEEEEEEEEEEEELLLLLLLLLLLLLDDDDDDDDD");
            //set damage back to default type if it is different
            if ( LevGun(ViewportOwner.Actor.Pawn.Weapon) != none &&
                 LevGun(ViewportOwner.Actor.Pawn.Weapon).getDType() != class'Enyara.DamTypeLev' )
                LevGun(ViewportOwner.Actor.Pawn.Weapon).setDType(class'Enyara.DamTypeLev');
    }

    return false;

}
function kcreset(){
    kcWdown1 = false;
    kcWup1 = false;
    kcWdown2 = false;
    kcMouse1Down1 = false;
    doubleTapPush = false;
    KCPushTimeStamp = 0.0;

    //should pull variable reset be seperate from push variable reset?
    kcSdown1 = false;
    kcSup1 = false;
    kcSdown2 = false;
    doubleTapPull = false;
    KCPullTimeStamp = 0.0;

    //pull while leving (throw while leving was the first one i did and is not handled the same as these...change later?)
    doubleTapPullWhileLev = false;

    LManager.printscreen("KCRESET");
}
/*
function bool KeyType( EInputKey Key, optional string Unicode )
{
    if (bIgnoreKeys)
        return true;

    if( Key>=0x20 )
    {
        if (TypedStr == ""){
            timeCounter = LManager.getLevelSeconds(); //timestamp from start of string typing
        }

        if( Unicode != "" )
            TypedStr = TypedStr $ Unicode;
        else
            TypedStr = TypedStr $ Chr(Key);
        ViewportOwner.Actor.ClientMessage("TypedStr:"@TypedStr@Unicode);
        return( false );
    }
}

*/
/*function bool KeyEvent(EInputKey Key, EInputAction Action, FLOAT Delta )
{
    if (MPC != none && LManager != none && LManager.AcceptingInput()){
        log("interaction is ready to read input...");
        //if (Action != IST_Press || Action != IST_Hold) return false;
        //log("KEY:"@Key);
      //  else if ( Key != FrontBackKey || Key != UpDownKey || Key != LeftRightKey ||
      //            Key != PosDir || Key != NegDir ) return false;
        if (Action == IST_Press){
            log("KEY:"@Key);
            switch (Key){
            case PosDir:
                pos = true;
                SetAxisDirection(true);
                break;
            case NegDir:
                neg = true;
                SetAxisDirection(false);
                break;
            case UpDownKey:
                if (pos || neg) UpDown.bActive = true;
                break;
            case LeftRightKey:
                if (pos || neg) LeftRight.bActive = true;
            case FrontBackKey:
                if (pos || neg) FrontBack.bActive = true;
                break;
            Default:
                break;
            } //end of switch statement
        } //end of else if ( IST_PRESS)
        else if ( Action == IST_Release ){
             switch (Key){
             case IK_LeftMouse:
                return false;
             case PosDir:
                pos = false;
                //:TODO: what if neg is still being held?
                return false;
                break;
             case NegDir:
                neg = false;
                return false;
                //:TODO: what if pos is still being held? need some kind of scan after a 'direction' is let go
                break;
             case UpDownKey:
                UpDown.bActive = false;
                break;
             case LeftRightKey:
                LeftRight.bActive = false;
                break;
             case FrontBackKey:
                FrontBack.bActive = false;
                break;
             default:
                break;
             } //end of switch
        } //end of else if( IST_Release)
        else{
            return false;
        }
        log ("interaction return true");
        logAxis();
        return true;
    } //end of 'accepting input'
    return false;

}


//################## Quick Setting Fxns (flip on axis) #####################
//sets all the 'direction' variables of AxisDir types
function SetAxisDirection(bool b){
    UpDown.direction = b;
    LeftRight.direction = b;
    FrontBack.direction = b;
}
//##########################################################################

function logAxis(){
    log("## AXIS LOG");
    log("# UpDown: bActive"@UpDown.bActive$", direction"@UpDown.direction);
    log("# LeftRight: bActive"@LeftRight.bActive$", direction"@LeftRight.direction);
    log("# FrontBack: bActive"@FrontBack.bActive$", direction"@FrontBack.direction);
}
*/

function string debugKeyTranslate(EInputKey Key, EInputAction Action) {
    local int k, a;
    local string sKey, sAction;
    k = Key;
    a = Action;
    switch (k){
    case 1:
        sKey = "Mouse1";
        break;
    case 87:
        sKey = "W";
        break;
    case 65:
        sKey = "A";
        break;
    case 83:
        sKey = "S";
        break;
    case 68:
        sKey = "D";
        break;
    default:
        break;
    }
    switch (a){
    case 0:
        sAction = "None";
        break;
    case 1:
        sAction = "Press";
        break;
    case 2:
        sAction = "Hold";
        break;
    case 3:
        sAction = "Release";
        break;
    case 4:
        sAction = "Axis";
        break;
    default:
        break;
    }

    return(sAction@sKey);

}

defaultproperties{
    bActive = True
    bIgnoreKeys = true
    bLev = false
    bRequiresTick = true;
    LevAxis = vect(0,0,0)
    //UpKey = Interactions.IK_MouseWheelUp
    //DownKey = Interactions.IK_MouseWheelDown
    UpKey = IK_E
    DownKey = IK_Q
    FrontKey = IK_W
    BackKey = IK_S
    RightKey = IK_D
    LeftKey = IK_A
    bLeftMouseDown = false
    uDown = false
    dDown = false
    lDown = false
    rDown = false
    fDown = false
    bDown = false
    ShiftDown = false
}
